package com.lzy.wzy.service.imp;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.Feature;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.gson.Gson;
import com.lzy.wzy.constant.MyConstant;
import com.lzy.wzy.exception.BingDingTemplateException;
import com.lzy.wzy.mapper.TemplateMapper;
import com.lzy.wzy.mapper.UserMapper;
import com.lzy.wzy.mapper.WorkMapper;
import com.lzy.wzy.model.*;
import com.lzy.wzy.result.ResponseCode;
import com.lzy.wzy.result.Result;
import com.lzy.wzy.sel.PtInfo;
import com.lzy.wzy.service.TemplateService;
import com.lzy.wzy.token.MyUsernamePasswordToken;
import com.lzy.wzy.utils.PatternUtils;
import com.lzy.wzy.utils.*;
import com.lzy.wzy.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.formula.functions.T;
import org.flowable.engine.IdentityService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.idm.api.User;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class TemplateServiceImp implements TemplateService {
    @Autowired
    private WorkMapper workMapper;

    @Autowired
    private TemplateMapper templateMapper;

    @Autowired
    private WorkOrderUtils workOrderUtils;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private Gson gson;

    @Autowired
    private RuntimeService runtimeService;


    @Autowired
    private IdentityService identityService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    //一级模板key
    private final static String TEMPLATE_KEY = "template:parentT:";

    //二级子模板key
    private final static String CHILD_TEMPLATE_KEY = "template:childT:";


    private final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");


    /*
     * @Author wzy
     * @Description //TODO 下发模板信息，工单部分信息，以及生产数据
     * @Date 2021/8/20 17:34
     * @Param * @param: id 模板id
     * @param: workOrderNumber 工单号
     * @return com.lzy.wzy.result.Result<com.lzy.wzy.vo.TemplateVo>
     **/
    @Transactional
    @Override
    public Result<TemplateVo> doQueryTemplate(int id, String workOrderNumber) {
        Integer idf = templateMapper.queryTemplateIdf(id);
        if (idf == null) {
            return Result.failure("不存在此模板");
        }
        String status = workMapper.getWorkOrderStatus(workOrderNumber);
        if (idf == 1) {
            if (!(MyConstant.WorkOrderStatus.FINISHED.equals(status) || MyConstant.WorkOrderStatus.CASECLOSE.equals(status))) {
                return Result.failure("模板已被禁用");
            }
        }
        //包装一级模板key
        String key = level1Key(id);
        //从redis 获取此模板
        String result = stringRedisTemplate.opsForValue().get(key);
        TemplateHeadVo templateHeadVo = null;
        //申明响应vo
        TemplateVo templateVo = new TemplateVo();
        //申明字段集合
        List<String> fields = new LinkedList<>();
        //向字段集合添加新字段 id
        fields.add("id");
        //获取此模板下所有字段
        List<String> allFields = templateMapper.getTemplateAllFields(id);
        //若redis存在此模板则直接包装模板头信息
        if (null != result) {
            templateHeadVo = gson.fromJson(result, TemplateHeadVo.class);
        }
        //将 headvo 利用 spring 工具类复制到 响应 vo， 查询出来的集合添加到申明字段集合
        if (null != templateHeadVo && !allFields.isEmpty()) {
            BeanUtils.copyProperties(templateHeadVo, templateVo);
            fields.addAll(allFields);
        } else {
            //若redis不存在此模板则向数据库查询
            List<TemplateBean> templateBeans = templateMapper.queryTemplateProcess(id);
            //设置响应  vo 参数
            templateVo.setLeaveOneTemplateName(templateBeans.get(0).getLeaveOneName());
            templateVo.setLeaveOneTemplateId(id);
            Map<String, Integer> leaveTwoMap = new LinkedHashMap<>();
            Set<String> leaveThreeSet = new LinkedHashSet<>();
            String leaveTwoName;
            //统计二级模板长度
            for (TemplateBean templateBean : templateBeans) {
                leaveTwoName = templateBean.getLeaveTwoName();
                if (leaveTwoMap.containsKey(leaveTwoName)) {
                    leaveTwoMap.put(leaveTwoName, leaveTwoMap.get(leaveTwoName) + 1);
                } else {
                    leaveTwoMap.put(leaveTwoName, 1);
                }
                leaveThreeSet.add(templateBean.getLeaveThreeName());
                fields.add(templateBean.getFieldName());
            }
            templateVo.setLeaveTwoTemplateName(leaveTwoMap);
            templateVo.setLeaveThreeTemplateName(leaveThreeSet);
            TemplateHeadVo headVo = new TemplateHeadVo();
            //将响应vo 模板信息 复制到 模板vo 并存储到redis缓存
            BeanUtils.copyProperties(templateVo, headVo);
            stringRedisTemplate.opsForValue().set(key, JSONObject.toJSONString(headVo));
        }
        //查询此模板对应的表名
        String tableName = templateMapper.queryTableNameByTemplateId(id);

        //模板生产数据处理
        List<LinkedHashMap<String, Object>> bodyData = processData(tableName, fields, workOrderNumber);
        //获取工单部分信息
        LinkedHashMap<String, Object> map = workMapper.getWorkOrderHeaderInformation(workOrderNumber);

        templateVo.setFieldName(fields);
        //对响应数据id加密
        templateVo.setBody(workOrderUtils.encryptionProcessing(bodyData));
        templateVo.setHeads(workOrderUtils.getHeaderInfo(map));
        return Result.success(templateVo);
    }

    /*
     * @Author wzy
     * @Description //TODO 生产数据上传
     * @Date 2021/8/20 17:41
     * @Param * @param: upTemplateDataBean
     * @return com.lzy.wzy.result.Result<org.apache.poi.ss.formula.functions.T>
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<T> doUpTemplateData(UpTemplateDataBean upTemplateDataBean) {
        try {
            //获取一级模板id
            int templateId = Integer.parseInt(upTemplateDataBean.getLeaveOneTemplateId());
            String workOrderNumber = upTemplateDataBean.getWorkOrderNumber();

            String serialNumber = workOrderNumber + templateId;
            ProductionBean productionBean = templateMapper.queryProductionOperation(serialNumber);
            if (productionBean != null) {
                MyUsernamePasswordToken token = (MyUsernamePasswordToken) SecurityContextHolder.getContext().getAuthentication();
                String userId = (String) token.getPrincipal();
                LocalDateTime now = LocalDateTime.now();
                if (MyConstant.ProductOperation.LOCK == productionBean.getStatus()) {
                    if (!userId.equals(productionBean.getProducer())) {
                        if (productionBean.getProductionTime().plusMinutes(5).isBefore(now)) {
                            if (productionBean.getLastTime() != null) {
                                if (productionBean.getLastTime().plusMinutes(5).isBefore(now)) {
                                    return Result.failure("对方已经长时间未操作，请点击开始生产");
                                }
                            } else {
                                return Result.failure("对方已经长时间未操作，请点击开始生产");
                            }
                        }
                        return Result.failure("正在生产，请稍等");
                    }
                } else {
                    return Result.failure("提交失败");
                }
            } else {
                return Result.failure("提交失败");
            }

            //获取提交的生产数据
            List<LinkedHashMap<String, Object>> list = upTemplateDataBean.getBody();
            Integer quantity = workMapper.getProductQuantityByWorkOrderNumber(workOrderNumber);
            if (list.size() > quantity) {
                return Result.failure("机器超过计划生产数量");
            }
            String status = workMapper.getWorkOrderStatus(workOrderNumber);
            //完工工单和结案工单不可提交数据
            if (MyConstant.WorkOrderStatus.FINISHED.equals(status) || MyConstant.WorkOrderStatus.CASECLOSE.equals(status)) {
                return Result.failure("工单已完工");
            }


            //获取软件版本
            String softVersion = upTemplateDataBean.getSoftVersion();
            softVersion = softVersion.trim();
            //保存软件版本
            if (PatternUtils.verifySoftVersion(softVersion)) {
                String version = workMapper.getSoftVersionByNumber(workOrderNumber);
                if (!softVersion.equals(version) && MyConstant.WorkOrderStatus.RELEASE.equals(status)) {
                    workMapper.updateSoftVersion(softVersion, workOrderNumber);
                }
            } else {
                throw new RuntimeException("软件版本格式错误");
            }
            //获取数据列名
            List<String> allFields = templateMapper.getTemplateAllFields(templateId);
            //获取上报字段
            List<String> fields = upTemplateDataBean.getFieldName();

            //验证提交数据是否合法
            workOrderUtils.verifyTheReportedData(allFields, fields, list);

            //查询 模板 表名
            String tableName = templateMapper.queryTableNameByTemplateId(templateId);

            //有序 map 集合 建表
            Map<String, String> fieldMap = new LinkedHashMap<>();
            if (templateMapper.existTable(tableName) == 0) {
                fieldMap.put("tableName", tableName);
                for (String filed : fields) {
                    if (filed.startsWith("long")) {
                        fieldMap.put(filed, "text");
                    } else {
                        fieldMap.put(filed, "varchar(128)");
                    }
                }
                fieldMap.put("workOrderNumber", "varchar(64)");
                log.info("创建表");

                //创建新表
                templateMapper.createTable(fieldMap);

                //创建索引
                templateMapper.createIndex(tableName);
            }


            //向字段集合添加新字段
            fields.add("workOrderNumber");
            //获取未上报之前的数据
            List<LinkedHashMap<String, Object>> beforeData = processData(tableName, fields, workOrderNumber);

            if (list.isEmpty() && !beforeData.isEmpty()) {
                templateMapper.emptyRecord(tableName, workOrderNumber);
                String info = workOrderUtils.getWorkOrderTestProcessDataModifyInfo(beforeData, list);
                workOrderUtils.recordModificationInformation(workOrderNumber, info, 2, templateId);
                return Result.success("删除成功");
            }

            //向上报数据添加 工单号
            for (LinkedHashMap<String, Object> data : list) {
                data.put("workOrderNumber", workOrderNumber);
            }

            //对非空id进行解码操作
            workOrderUtils.decryptionProcessing(list);

            //新提交数据与旧数据比较
            if (!list.equals(beforeData)) {

                if (workMapper.getSingleWorkOrder(workOrderNumber) > 0) {

                    //对空id进行 id赋值
                    workOrderUtils.packageId(workOrderNumber, beforeData, list);
                    //拷贝集合
                    List<LinkedHashMap<String, Object>> data = workOrderUtils.deepCopy(list);


                    //数据处理获取上报数据操作信息
                    String dataModifyInfo = workOrderUtils.getWorkOrderTestProcessDataModifyInfo(beforeData, list);

                    //清空表数据-
                    System.out.println("workMapper.emptyRecord(tableName, workOrderNumber) = " + templateMapper.emptyRecord(tableName, workOrderNumber));
                    //批量插入数据
                    System.out.println("workMapper.batchInsert(tableName, fieldNames, list) = " + templateMapper.batchInsert(tableName, fields, data));


                    if (StringUtils.isNotBlank(dataModifyInfo)) {
                        workOrderUtils.recordModificationInformation(workOrderNumber, dataModifyInfo, 2, templateId);
                    }
                    if (MyConstant.WorkOrderStatus.RELEASE.equals(status)) {
                        //更新工单状态为在制
                        workMapper.updateWorkOrderStatus(MyConstant.WorkOrderStatus.InSystem, workOrderNumber);
                        //保存生产日期
                        workMapper.saveProductDate(LocalDate.now(), workOrderNumber);
                    }
                    //更新操作时间
                    templateMapper.saveLastTime(LocalDateTime.now(), serialNumber);
                }
            } else {
                return Result.failure("请填写数据");
            }
        } catch (Exception e) {
            //异常手动回滚
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Result.failure();
        }
        return Result.success();
    }


    /*
     * @Author wzy
     * @Description //TODO 绑定模板
     * @Date 2021/8/20 17:44
     * @Param * @param: productCode
     * @param: templateId
     * @return com.lzy.wzy.result.Result<org.apache.poi.ss.formula.functions.T>
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<T> doBindingTemplate(String productCode, int templateId) {
        workOrderUtils.checkTemplate(templateId);
        //查询此产品编码和此模板是否一级绑定
        if (templateMapper.getWorkOrderTemplateByProductCode(productCode, templateId) == 0) {
            if (templateMapper.bindingTemplate(productCode, templateId) > 0) {
                log.info("模板绑定成功");
                return Result.success("绑定成功");
            }
        }
        return Result.failure("绑定失败");
    }

    /*
     * @Author wzy
     * @Description //TODO 一级模板信息预览  与模板下发部分代码一致不做注释
     * @Date 2021/8/20 17:44
     * @Param * @param: templateId
     * @return com.lzy.wzy.result.Result<com.lzy.wzy.vo.TemplateHeadVo>
     **/
    @Override
    public Result<PreviewVo> doPreviewTemplate(int templateId) {
        String key = level1Key(templateId);
        String result = stringRedisTemplate.opsForValue().get(key);
        TemplateHeadVo templateHeadVo = null;
        if (null != result) {
            templateHeadVo = gson.fromJson(result, TemplateHeadVo.class);
        }
        if (null == templateHeadVo) {
            List<TemplateNameBean> templateBeans = templateMapper.queryTemplateName(templateId);
            if (templateBeans.isEmpty()) {
                return Result.failure();
            }
            templateHeadVo = new TemplateHeadVo();
            templateHeadVo.setLeaveOneTemplateId(templateBeans.get(0).getLeaveOneId());
            templateHeadVo.setLeaveOneTemplateName(templateBeans.get(0).getLeaveOneName());
            Map<String, Integer> leaveTwoMap = new LinkedHashMap<>();
            Set<String> leaveThreeSet = new LinkedHashSet<>();
            String leaveTwoName;
            //统计二级模板长度
            for (TemplateNameBean templateBean : templateBeans) {
                leaveTwoName = templateBean.getLeaveTwoName();
                if (leaveTwoMap.containsKey(leaveTwoName)) {
                    leaveTwoMap.put(leaveTwoName, leaveTwoMap.get(leaveTwoName) + 1);
                } else {
                    leaveTwoMap.put(leaveTwoName, 1);
                }
                leaveThreeSet.add(templateBean.getLeaveThreeName());
            }
            templateHeadVo.setLeaveTwoTemplateName(leaveTwoMap);
            templateHeadVo.setLeaveThreeTemplateName(leaveThreeSet);
            stringRedisTemplate.opsForValue().set(key, JSON.toJSONString(templateHeadVo));
        }
        PreviewBean previewBean = templateMapper.getFirstLevelTemplateStatusAndIdf(templateId);
        List<String> codes = templateMapper.getProductCodeByTemplateId(templateId);
        PreviewVo previewVo = new PreviewVo(templateHeadVo, previewBean.getResult(), previewBean.getFlag(), codes);
        return Result.success(previewVo);
    }

    /*
     * @Author wzy
     * @Description //TODO 获取所有三级模板
     * @Date 2021/8/20 17:45
     * @Param * @param: pageNum
     * @param: pageSize
     * @return com.lzy.wzy.result.Result<com.github.pagehelper.PageInfo<com.lzy.wzy.model.LevelOneTemplateBean>>
     **/
    @Override
    public Result<PageInfo<LevelOneTemplateBean>> doGetAllLeaveThreeTemplate(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        PageInfo<LevelOneTemplateBean> pageInfo = new PageInfo<>(templateMapper.getAllLeaveThreeTemplate());
        return Result.success(pageInfo);
    }

    /*
     * @Author wzy
     * @Description //TODO 获取所有二级模板
     * @Date 2021/8/20 17:45
     * @Param * @param: pageNum
     * @param: pageSize
     * @return com.lzy.wzy.result.Result<com.github.pagehelper.PageInfo<com.lzy.wzy.model.LevelOneTemplateBean>>
     **/
    @Override
    public Result<PageInfo<LevelOneTemplateBean>> doGetAllLeaveTwoTemplate(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        PageInfo<LevelOneTemplateBean> pageInfo = new PageInfo<>(templateMapper.getAllLeaveTwoTemplate());
        return Result.success(pageInfo);
    }

    /*
     * @Author wzy
     * @Description //TODO 检验三级模板是否存在
     * @Date 2021/8/20 17:45
     * @Param * @param: templateName
     * @return com.lzy.wzy.result.Result<org.apache.poi.ss.formula.functions.T>
     **/
    @Override
    public Result<T> doCheckLeaveThreeTemplateName(String templateName) {
        if (templateMapper.getLeaveThreeTemplateByTemplateName(templateName) > 0) {
            return Result.failure("此模板已存在");
        }
        return Result.success();
    }

    /*
     * @Author wzy
     * @Description //TODO 添加三级模板
     * @Date 2021/8/20 17:46
     * @Param * @param: templateName
     * @param: fieldName
     * @return com.lzy.wzy.result.Result<org.apache.poi.ss.formula.functions.T>
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<T> doAddLeaveThreeTemplate(String templateName, String fieldName) {
        if (templateMapper.getLeaveThreeTemplateByTemplateName(templateName) < 1
                && templateMapper.getLevelThreeTemplateByFieldName(fieldName) < 1
                && templateMapper.addLeaveThreeTemplate(templateName, fieldName) > 0) {
            return Result.success("添加成功");
        }
        return Result.failure("添加失败");
    }

    /*
     * @Author wzy
     * @Description //TODO 添加二级模板
     * @Date 2021/8/20 17:46
     * @Param * @param: upFirstLevelTemplateVo
     * @return com.lzy.wzy.result.Result<org.apache.poi.ss.formula.functions.T>
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<T> doAddLeaveTwoTemplate(UpFirstLevelTemplateVo upFirstLevelTemplateVo) {
        String templateName = upFirstLevelTemplateVo.getTemplateName();
        List<BingDingTemplate> list = upFirstLevelTemplateVo.getBody();
        //检查模板名称
        if (PatternUtils.checkTemplateName(templateName)) {
            return Result.invalidFormat("模板格式错误");
        }
        //判断此模板是否存在
        Integer templateId = templateMapper.getLeaveTwoTemplateByTemplateName(templateName);
        if (null != templateId) {
            return Result.to(ResponseCode.EXISTED.getCode(), "模板已存在");
        }
        //检查是否提交了相同二级模板
        Set<BingDingTemplate> templates = new HashSet<>(list);
        if (templates.size() != list.size()) {
            return Result.failure("禁止添加重复工步");
        }
        //添加二级模板
        if (templateMapper.addLeaveTwoTemplate(templateName) > 0) {
            templateId = templateMapper.getLeaveTwoTemplateByTemplateName(templateName);
            Set<Integer> set = new HashSet<>();
            for (BingDingTemplate bingDingTemplate : list) {
                bingDingTemplate.setParentId(templateId);
                set.add(bingDingTemplate.getChildId());
            }
            //判断不同二级模板是否存在相同三级模板
            int size = list.size();
            if (set.size() != size) {
                throw new BingDingTemplateException("非法模板!禁止添加重复工步");
            }
            //校验 提交的模板是否属于三级模板
            if (!list.isEmpty() && templateMapper.getLevelThreeTemplateByIds(list) == size) {
                list.sort(Comparator.comparingInt(BingDingTemplate::getOrderId));
                //绑定映射关系
                if (templateMapper.bingDingTwoTemplate(list) > 0) {
                    log.info("二三级模板绑定成功");
                    return Result.success();
                }
                throw new BingDingTemplateException("绑定失败");
            }
            throw new BingDingTemplateException("非法模板");
        }
        return Result.failure();
    }

    /*
     * @Author wzy
     * @Description //TODO 添加一级模板 流程和添加二级模板基本一致 不做注释
     * @Date 2021/8/20 17:48
     * @Param * @param: upFirstLevelTemplateVo
     * @return com.lzy.wzy.result.Result<org.apache.poi.ss.formula.functions.T>
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<T> doAddLeaveOneTemplate(UpFirstLevelTemplateVo upFirstLevelTemplateVo) {
        String templateName = upFirstLevelTemplateVo.getTemplateName();
        String templateAlias = upFirstLevelTemplateVo.getTemplateAlias();
        if (templateMapper.existTable(templateAlias) > 0) {
            return Result.to(ResponseCode.EXISTED.getCode(), "此数据表已存在");
        }
        List<BingDingTemplate> list = upFirstLevelTemplateVo.getBody();
        if (PatternUtils.checkTemplateName(templateName) || !PatternUtils.checkLeaveOneTemplateAlias(templateAlias)) {
            return Result.invalidFormat("非法参数");
        }
        Integer templateId = templateMapper.getLeaveOneTemplateByTemplateName(templateName, templateAlias);
        if (null != templateId) {
            return Result.to(ResponseCode.EXISTED.getCode(), "模板已存在");
        }
        Set<BingDingTemplate> templates = new HashSet<>(list);
        if (templates.size() != list.size()) {
            return Result.failure("禁止添加重复工序模板");
        }

        MyUsernamePasswordToken token = (MyUsernamePasswordToken) SecurityContextHolder.getContext().getAuthentication();
        if (templateMapper.addLeaveOneTemplate(templateName, templateAlias, MyConstant.TemplateStatus.PENDING_REVIEW, (String) token.getPrincipal(), LocalDate.now()) > 0) {
            templateId = templateMapper.getLeaveOneTemplateByTemplateName(templateName, templateAlias);
            List<Integer> ids = new ArrayList<>();
            for (BingDingTemplate bingDingTemplate : list) {
                bingDingTemplate.setParentId(templateId);
                ids.add(bingDingTemplate.getChildId());
            }
            //校验 提交的模板是否属于二级模板
            if (!list.isEmpty() && templateMapper.getLevelTwoTemplateByIds(ids) == list.size()) {
                //获取提交的二级模板的所有子模板
                List<String> childTemplate = templateMapper.getLevelTwoTemplateChildTemplate(ids);
                Set<String> set = new HashSet<>(childTemplate);

                if (childTemplate.size() != set.size()) {
                    throw new BingDingTemplateException("请检查工序模板,禁止提交重复工步");
                }

                list.sort(Comparator.comparingInt(BingDingTemplate::getOrderId));
                if (templateMapper.bingDingOneTwoLeaveTemplate(list) > 0) {
                    log.info("一二级模板绑定成功");
                    return Result.success();
                }
                throw new BingDingTemplateException("绑定失败");
            }
            throw new BingDingTemplateException("非法模板");
        }
        return Result.failure();
    }

    /*
     * @Author wzy
     * @Description //TODO 获取所有一级模板
     * @Date 2021/8/20 17:49
     * @Param * @param:
     * @return com.lzy.wzy.result.Result<java.util.List<com.lzy.wzy.model.LevelOneTemplateBean>>
     **/
    @Override
    public Result<List<LevelOneTemplateBean>> doGetAllFirstLevelTemplates() {
        return Result.success(templateMapper.getAllFirstLevelTemplates());
    }

    /*
     * @Author wzy
     * @Description //TODO 获取所有已经批准使用的一级模板
     * @Date 2021/8/20 17:49
     * @Param * @param:
     * @return com.lzy.wzy.result.Result<java.util.List<com.lzy.wzy.model.LevelOneTemplateBean>>
     **/
    @Override
    public Result<List<LevelOneTemplateBean>> doGetAllFirstLevelTemplatesPassed() {
        return Result.success(templateMapper.getAllFirstLevelTemplatesPassed(MyConstant.TemplateStatus.PASSED));
    }

    /*
     * @Author wzy
     * @Description //TODO 查询一级模板信息
     * @Date 2021/8/20 17:50
     * @Param * @param: pageNum
     * @param: pageSize
     * @return com.lzy.wzy.result.Result<com.github.pagehelper.PageInfo<com.lzy.wzy.model.FirstLevelTemplateInformationBean>>
     **/
    @Override
    public Result<PageInfo<FirstLevelTemplateInformationBean>> doGetAllFirstLevelTemplateInformation(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        PageInfo<FirstLevelTemplateInformationBean> pageInfo = new PageInfo<>(templateMapper.getAllFirstLevelTemplateInformation());
        return Result.success(pageInfo);
    }

    /*
     * @Author wzy
     * @Description //TODO 刷新生产上报数据
     * @Date 2021/8/20 17:50
     * @Param * @param: templateId
     * @param: fieldNames
     * @param: workOrderNumber
     * @return com.lzy.wzy.result.Result<java.util.List<java.util.LinkedHashMap<java.lang.String,java.lang.Object>>>
     **/
    @Override
    public Result<List<LinkedHashMap<String, Object>>> doRefreshBodyData(int templateId, List<String> fieldNames, String workOrderNumber) {
        String tableName = templateMapper.queryTableNameByTemplateId(templateId);
        List<LinkedHashMap<String, Object>> bodyData = processData(tableName, fieldNames, workOrderNumber);

        return Result.success(workOrderUtils.encryptionProcessing(bodyData));
    }

    /*
     * @Author wzy
     * @Description //TODO 异常上报
     * @Date 2021/8/20 17:50
     * @Param * @param: exceptionReportBean
     * @return com.lzy.wzy.result.Result<org.apache.poi.ss.formula.functions.T>
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<T> doReportAbnormalInformation(ExceptionReportBean exceptionReportBean, MultipartFile file) throws IOException {
        String workOrderNumber = exceptionReportBean.getWorkOrderNumber();
        if (!PatternUtils.checkWorkOrderNumber(workOrderNumber)) {
            return Result.invalidFormat();
        }
        String status = workMapper.getWorkOrderStatus(workOrderNumber);
        if (MyConstant.WorkOrderStatus.EXCEPTION.equals(status)) {
            status = workMapper.getExceptionWorkOrderStatus(workOrderNumber);
        }
        if (!(MyConstant.WorkOrderStatus.CASECLOSE.equals(status) || MyConstant.WorkOrderStatus.RELEASE.equals(status))) {
            MyUsernamePasswordToken token = (MyUsernamePasswordToken) SecurityContextHolder.getContext().getAuthentication();
            String userUuid = (String) token.getPrincipal();
            String path = null;
            if (file != null) {
                String filename = file.getOriginalFilename();
                assert filename != null;
                String suffix = filename.substring(filename.lastIndexOf("."));
                String fileName = UUID.randomUUID().toString().replace("-", "") + suffix;
                File file1 = new File("/usr/local/run/file/" + fileName);
                path = file1.getPath();
                file.transferTo(file1);
            }
            exceptionReportBean.setReporter(userUuid);
            exceptionReportBean.setReporterDate(LocalDateTime.now());
            exceptionReportBean.setStatus(MyConstant.ReportStatus.PENDING);
            exceptionReportBean.setWorkOrderStatus(status);
            exceptionReportBean.setReportFilePath(path);
            if (templateMapper.saveExceptionInfo(exceptionReportBean) > 0) {
                if (!MyConstant.WorkOrderStatus.MAJOR_EXCEPTION.equals(status) && !MyConstant.WorkOrderStatus.EXCEPTION.equals(status)) {
                    workMapper.updateWorkOrderStatus(MyConstant.WorkOrderStatus.EXCEPTION, exceptionReportBean.getWorkOrderNumber());
                }

                return Result.success("异常上报成功");

            } else {
                return Result.failure("异常上报失败");
            }
        }
        return Result.failure("不可上报");
    }

    /*
     * @Author wzy
     * @Description //TODO 生产数据修改所有记录
     * @Date 2021/8/20 17:51
     * @Param * @param: workOrderNumber
     * @param: templateId
     * @return com.lzy.wzy.result.Result<com.lzy.wzy.vo.ModifyRecordVo>
     **/
    @Override
    public Result<ModifyRecordVo> doViewTestDataModificationRecords(String workOrderNumber, int templateId) {
        //通过工单号，记录类型，模板id获取修改记录信息
        List<ModifyRecordBean> recordBeans = templateMapper.getWorkOrderTestDataModificationRecord(workOrderNumber, 2, templateId);
        //获取一级模板下面所有的字段
        List<LinkedHashMap<String, String>> allField = templateMapper.getThreeLeaveTemplateIdAndNameByOneId(templateId);
        Map<String, Object> fieldMap = new LinkedHashMap<>();
        //封装 列map
        for (LinkedHashMap<String, String> field : allField) {
            fieldMap.put(field.get("field_name"), field.get("template_name"));
        }
        //按照操作时间倒排序
        recordBeans.sort(Comparator.comparing(ModifyRecordBean::getModifyTime, Comparator.reverseOrder()));
        List<Map<String, String>> list = new ArrayList<>();

        List<Map<String, String>> maps;
        //往修改内容添加修改时间，和修改人
        for (ModifyRecordBean recordBean : recordBeans) {

            maps = JSON.parseObject(recordBean.getModifyContent(), new TypeReference<List<Map<String, String>>>() {
            }, Feature.OrderedField);
            for (Map<String, String> map : maps) {
                map.put("modifyTime", recordBean.getModifyTime().format(dtf));
                map.put("modifier", recordBean.getModifier());
            }
            list.addAll(maps);
        }


        List<Map<String, String>> collect = list.stream().sorted(Comparator.comparing(PublicUtils::comparingById))
                .collect(Collectors.toList());


        String key;
        List<List<String>> result = new LinkedList<>();
        //添加新响应字段
        List<Object> templateNames = new LinkedList<>(fieldMap.values());
        templateNames.add("操作时间");
        templateNames.add("操作者");
        templateNames.add("操作");

        List<String> relist;
        //将查询出来的数据添加到集合里面
        for (Map<String, String> map : collect) {
            relist = new ArrayList<>();
            for (Map.Entry<String, Object> entry : fieldMap.entrySet()) {
                key = entry.getKey();

                if (map.containsKey(key)) {
                    String val = String.valueOf(map.get(key));
                    relist.add(val);
                } else {
                    relist.add("");
                }
            }
            relist.add(String.valueOf(map.get("modifyTime")));
            relist.add(String.valueOf(map.get("modifier")));
            relist.add(String.valueOf(map.get("operating")));
            result.add(relist);
        }
        ModifyRecordVo modifyRecordVo = new ModifyRecordVo();
        modifyRecordVo.setResultList(result);
        modifyRecordVo.setTemplateNames(templateNames);

        return Result.success(modifyRecordVo);
    }


    /*
     * @Author wzy
     * @Description //TODO 返修工单绑定模板
     * @Date 2021/8/20 17:55
     * @Param * @param: reworkOrderNumber
     * @param: templateId
     * @return com.lzy.wzy.result.Result<org.apache.poi.ss.formula.functions.T>
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<T> doReworkOrderBindTemplate(String reworkOrderNumber, int templateId) {
        workOrderUtils.checkTemplate(templateId);
        //检查此返修工单是否已经绑定模板
        if (templateMapper.getReworkOrderTemplateByNumber(reworkOrderNumber) == 0) {
            if (templateMapper.saveReworkTemplateInfo(reworkOrderNumber, templateId) > 0) {
                return Result.success("绑定成功");
            }
        }
        return Result.failure("绑定失败，或已经绑定模板");
    }

    /*
     * @Author wzy
     * @Description //TODO 更换产品编码绑定模板信息
     * @Date 2021/8/20 17:56
     * @Param * @param: productCode
     * @param: newTemplateId
     * @param: oldTemplateId
     * @return com.lzy.wzy.result.Result<org.apache.poi.ss.formula.functions.T>
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<T> doModifyProductAndTemplateBindingInformation(String productCode, int newTemplateId, int oldTemplateId) {
        workOrderUtils.checkTemplate(newTemplateId);
        workOrderUtils.checkTemplate(oldTemplateId);
        //检查此产品编码和此模板没有绑定，则添加绑定关系
        if (templateMapper.getWorkOrderTemplateByProductCode(productCode, newTemplateId) == 0 && templateMapper.updateProductCodeAndTemplateBindingInformation(productCode, newTemplateId, oldTemplateId) > 0) {
            return Result.success("修改成功");
        }
        return Result.failure("修改失败");
    }

    /*
     * @Author wzy
     * @Description //TODO 查询此工单任意模板下的最后一次数据的操作记录 包括操作人
     * @Date 2021/8/20 17:57
     * @Param * @param: workOrderNumber
     * @param: templateId
     * @return com.lzy.wzy.result.Result<com.lzy.wzy.vo.LastRecordVo>
     **/
    @Override
    public Result<LastRecordVo> doViewTheLastOperationRecord(String workOrderNumber, int templateId) {
        workOrderUtils.checkTemplate(templateId);
        //查询此工单对应某个模板下所有的操作记录
        List<ModifyRecordBean> recordBeans = templateMapper.getWorkOrderTestDataModificationRecord(workOrderNumber, 2, templateId);
        //获取此模板对应的所有三级模板字段和名称
        List<LinkedHashMap<String, String>> allField = templateMapper.getThreeLeaveTemplateIdAndNameByOneId(templateId);
        //初始化存放模板 name和field的map
        Map<String, Object> fieldMap = new LinkedHashMap<>();
        //封装 列map
        for (LinkedHashMap<String, String> field : allField) {
            fieldMap.put(field.get("field_name"), field.get("template_name"));
        }
        //将操作记录按照时间排序
        recordBeans.sort(Comparator.comparing(ModifyRecordBean::getModifyTime));
        //初始化分组list
        List<Map<String, String>> list = new ArrayList<>();

        //遍历所有操作content将其转换为 List<Map<String,Object> 并添加修改人
        List<Map<String, String>> maps;
        for (ModifyRecordBean recordBean : recordBeans) {

            maps = JSON.parseObject(recordBean.getModifyContent(), new TypeReference<List<Map<String, String>>>() {
            }, Feature.OrderedField);
            for (Map<String, String> map : maps) {
                map.put("modifier", recordBean.getModifier());
            }
            list.addAll(maps);
        }
        //申明字段key
        String key;

        //将所有操作记录进行id分组
        Map<String, List<Map<String, String>>> listMap = list.stream().collect(Collectors.groupingBy(map -> map.get("id")));

        LinkedHashMap<String, List<Map<String, String>>> resultMap=new LinkedHashMap<>();

        listMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEachOrdered(e -> resultMap.put(e.getKey(),e.getValue()));

        //存放此次遍历结果
        Map<String, Object> temp;


        //最终数据集合
        List<Map<String, Object>> resultList = new ArrayList<>();

        //存放每一格操作记录人
        Map<String, Object> names;

        //最终操作人集合
        List<Map<String, Object>> resultNames = new ArrayList<>();

        //遍历分组后的 map
        for (Map.Entry<String, List<Map<String, String>>> entry : resultMap.entrySet()) {
            //容器初始化
            temp = new LinkedHashMap<>();
            names = new LinkedHashMap<>();

            //遍历每一组里面的map
            for (Map<String, String> map : entry.getValue()) {
                //若出现 delete操作，则回滚这一组所有数据，此处直接释放掉map
                if (MyConstant.WorkOrderOperation.DELETE.equals(map.get("operating"))) {
                    temp.clear();
                    temp = null;
                    names.clear();
                    names = null;
                    break;
                }
                //遍历字段map
                for (Map.Entry<String, Object> field : fieldMap.entrySet()) {
                    //key赋值
                    key = field.getKey();
                    //若操作记录有操作过此字段则向 temp put此字段和操作后的数据,并记录 对应的操作者
                    if (map.containsKey(key)) {
                        temp.put(key, map.get(key));
                        names.put(key, map.get("modifier"));
                    }
                }
            }
            //若数据存放map没有出现delete操作则向最终结果list添加记录
            if (null != temp) {
                resultNames.add(names);
                resultList.add(temp);
            }
        }
        //将数据map没有操作的过字段补上""
        resultList = handlerMap(fieldMap, resultList);
        //将名字map没有操作的过字段补上""
        resultNames = handlerMap(fieldMap, resultNames);

        //将map包装成最终结果集合
        List<List<Object>> r1 = packageMap(resultNames);


        //将map包装成最终结果集合
        List<List<Object>> r2 = packageMap(resultList);

        //此模板下三级模板的所有模板名称集合
        List<Object> r3 = new ArrayList<>(fieldMap.values());

        LastRecordVo lastRecordVo = new LastRecordVo(r3, r1, r2);
        return Result.success(lastRecordVo);
    }

    /*
     * @Author wzy
     * @Description //TODO 获取所有已批准使用的模板和与模板建立绑定关系的产品编码
     * @Date 2021/8/20 17:59
     * @Param * @param:
     * @return com.lzy.wzy.result.Result<com.lzy.wzy.vo.ProductCodeAndTemplateVo>
     **/
    @Override
    public Result<ProductCodeAndTemplateVo> doGetAllProductCodesAndTemplates() {
        List<LevelOneTemplateBean> template = templateMapper.getAllFirstLevelTemplatesPassed(MyConstant.TemplateStatus.PASSED);
        List<String> allProductCode = templateMapper.getAllProductCode();
        ProductCodeAndTemplateVo templateVo = new ProductCodeAndTemplateVo(template, allProductCode);
        return Result.success(templateVo);
    }

    /*
     * @Author wzy
     * @Description //TODO 下发所有已批准模板和返修工单
     * @Date 2021/8/20 17:59
     * @Param * @param:
     * @return com.lzy.wzy.result.Result<com.lzy.wzy.vo.ReworkOrderAndTemplateVo>
     **/
    @Override
    public Result<ReworkOrderAndTemplateVo> doGetAllRepairWorkOrdersAndTemplates() {
        List<LevelOneTemplateBean> template = templateMapper.getAllFirstLevelTemplatesPassed(MyConstant.TemplateStatus.PASSED);
        List<String> reworkOrder = workMapper.getAllReworkOrder(MyConstant.WorkOrderStatus.RELEASE, MyConstant.WorkType.F);
        ReworkOrderAndTemplateVo reworkOrderAndTemplateVo = new ReworkOrderAndTemplateVo(template, reworkOrder);
        return Result.success(reworkOrderAndTemplateVo);
    }

    /*
     * @Author wzy
     * @Description //TODO 获取所有非下达返修工单
     * @Date 2021/10/27 15:39
     * @Param * @param:
     * @return com.lzy.wzy.result.Result<java.util.List<java.lang.String>>
     **/
    @Override
    public Result<ReworkOrderAndTemplateVo> doGetAllReworkOrderIsBinding() {
        List<LevelOneTemplateBean> template = templateMapper.getAllFirstLevelTemplatesPassed(MyConstant.TemplateStatus.PASSED);
        List<String> workOrders = workMapper.getAllIsBindingReworkOrderNumber();
        ReworkOrderAndTemplateVo reworkOrderAndTemplateVo = new ReworkOrderAndTemplateVo(template, workOrders);
        return Result.success(reworkOrderAndTemplateVo);
    }

    /*
     * @Author wzy
     * @Description //TODO 更新返修工单模板
     * @Date 2021/10/27 14:21
     * @Param * @param: workOrderNumber
     * @param: newTemplateId
     * @param: oldTemplateId
     * @return com.lzy.wzy.result.Result<org.apache.poi.ss.formula.functions.T>
     **/
    @Override
    public Result<T> doUpdateTheRepairWorkOrderTemplate(String workOrderNumber, int newTemplateId, int oldTemplateId) {
        Integer templateId = templateMapper.getTemplateIdByRework(workOrderNumber);
        if (templateId != null) {
            if (templateId == newTemplateId || newTemplateId == oldTemplateId) {
                return Result.failure("新模板不能与旧模板一样");
            }
            if (templateMapper.updateReworkOrderTemplate(workOrderNumber, newTemplateId, oldTemplateId) > 0) {
                return Result.success("更新成功");
            }
        }
        return Result.failure("更新失败");
    }


    /*
     * @Author wzy
     * @Description //TODO 通过返修工单获取模板id
     * @Date 2021/10/27 15:03
     * @Param * @param: workOrderNumber
     * @return com.lzy.wzy.result.Result<java.lang.Integer>
     **/
    @Override
    public Result<LevelOneTemplateBean> doGetTemplateInfoByRework(String workOrderNumber) {
        return Result.success(templateMapper.getTemplateNameByRework(workOrderNumber));
    }

    /*
     * @Author wzy
     * @Description //TODO 通过产品编码查询对应模板
     * @Date 2021/8/20 18:00
     * @Param * @param: productCode
     * @return com.lzy.wzy.result.Result<java.util.List<com.lzy.wzy.model.LevelOneTemplateBean>>
     **/
    @Override
    public Result<List<LevelOneTemplateBean>> doGetTheCorrespondingTemplateOfTheProductCode(String productCode) {
        return Result.success(templateMapper.getLevelOneTemplateByProductCode(productCode));
    }

    /*
     * @Author wzy
     * @Description //TODO 删除一级模板
     * @Date 2021/8/20 18:01
     * @Param * @param: templateId
     * @return com.lzy.wzy.result.Result<org.apache.poi.ss.formula.functions.T>
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<T> doDeleteTemplate(int templateId) {
        String key = level1Key(templateId);
        String tableName = templateMapper.queryTableNameByTemplateId(templateId);
        if (null != tableName
                && templateMapper.existTable(tableName) > 0
                && templateMapper.deleteTable(tableName) > 0) {
            log.info("删除对应表");
        }
        //删除记录表信息
        templateMapper.deleteTheTemplateModifyRecord(templateId);
        //删除redis 一级模板
        stringRedisTemplate.delete(key);

        //获取返修工单映射表此模板使用个数
        Integer rework = templateMapper.getReworkOrderByTemplateId(templateId);
        if (rework > 0) {
            //删除映射
            templateMapper.deleteReworkOrderMapping(templateId);
        }
        //获取对应产品编码
        List<String> productCodes = templateMapper.getProductCodeByTemplateId(templateId);
        if (!productCodes.isEmpty()) {
            //删除与产品编码映射
            if (templateMapper.deleteThisLevelOneTemplateCodeMapping(templateId) == productCodes.size()) {
                log.info("删除编码映射");
            } else {
                throw new RuntimeException("删除失败");
            }
        }
        String name = templateMapper.getLevelOneTemplateNameById(templateId);
        //删除此模板
        if (templateMapper.deleteThisLevelOneTemplate(templateId) > 0
                //删除与二级模板映射关系
                && templateMapper.deleteThisLevelOneTemplateMapping(templateId) > 0) {
            workOrderUtils.saveBulletin("删除流工单模板：", name, "工艺主管删除!!!");
            return Result.success("删除成功");
        }
        throw new RuntimeException("删除失败");
    }

    /*
     * @Author wzy
     * @Description //TODO 删除模板下的表信息
     * @Date 2021/8/20 18:01
     * @Param * @param: templateId
     * @return com.lzy.wzy.result.Result<org.apache.poi.ss.formula.functions.T>
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<T> doDeleteDataTable(int templateId) {
        String tableName = templateMapper.queryTableNameByTemplateId(templateId);
        if (null != tableName
                && templateMapper.existTable(tableName) > 0
                && templateMapper.deleteTable(tableName) > 0) {
            templateMapper.deleteTheTemplateModifyRecord(templateId);
            return Result.success("删除成功");
        }
        return Result.failure("删除失败,或此模板并未被使用");
    }

    /*
     * @Author wzy
     * @Description //TODO 更新一级模板状态
     * @Date 2021/8/20 18:02
     * @Param * @param: templateId
     * @param: templateName
     * @return com.lzy.wzy.result.Result<org.apache.poi.ss.formula.functions.T>
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<String> doUpdateFirstLevelTemplateStatus(int templateId, String templateName) {
        String status = templateMapper.getFirstLevelTemplateStatus(templateId);
        if (!MyConstant.TemplateStatus.PASSED.equals(status)
                && templateMapper.updateFirstLevelTemplateStatus(MyConstant.TemplateStatus.PASSED, templateId) > 0) {
            String tableName = templateMapper.queryTableNameByTemplateId(templateId);
            LinkedList<String> allFields = templateMapper.getTemplateAllFields(templateId);
            allFields.addFirst("id");
            allFields.addLast("workOrderNumber");
            //有序 map 集合 建表
            Map<String, String> fieldMap = new LinkedHashMap<>();
            if (templateMapper.existTable(tableName) == 0) {
                fieldMap.put("tableName", tableName);
                for (String filed : allFields) {
                    if (filed.startsWith("long")) {
                        fieldMap.put(filed, "text");
                    } else {
                        fieldMap.put(filed, "varchar(128)");
                    }
                }
                // fieldMap.put("workOrderNumber", "varchar(64)");
                log.info("创建表");

                //创建新表
                templateMapper.createTable(fieldMap);

                //创建工单号索引
                templateMapper.createIndex(tableName);

                //创建id索引
                templateMapper.createIdIndex(tableName);
            }
            return Result.to(ResponseCode.SUCCESS.getCode(), "更新成功", MyConstant.TemplateStatus.PASSED);
        }
        return Result.failure("更新失败");
    }

    /*
     * @Author wzy
     * @Description //TODO 获取二级及以下子模板信息
     * @Date 2021/8/20 18:02
     * @Param * @param: templateId
     * @return com.lzy.wzy.result.Result<com.lzy.wzy.vo.ChildTemplateVo>
     **/
    @Override
    public Result<ChildTemplateVo> dogGetChildTemplateInformation(int templateId) {
        String key = level2key(templateId);
        String result = stringRedisTemplate.opsForValue().get(key);
        ChildTemplateVo childTemplateVo;
        if (null != result) {
            childTemplateVo = gson.fromJson(result, ChildTemplateVo.class);
        } else {
            List<ChildTemplateNameBean> childTemplateNameBeans = templateMapper.getChildTemplateInformationByLevelTwoId(templateId);
            if (!childTemplateNameBeans.isEmpty()) {
                childTemplateVo = new ChildTemplateVo();
                childTemplateVo.setParentName(childTemplateNameBeans.get(0).getLevelTwo());
                List<String> list = new ArrayList<>();
                for (ChildTemplateNameBean templateNameBean : childTemplateNameBeans) {
                    list.add(templateNameBean.getLevelThree());
                }
                childTemplateVo.setParentLength(list.size());
                childTemplateVo.setChildName(list);
                stringRedisTemplate.opsForValue().set(key, JSON.toJSONString(childTemplateVo));
            } else {
                return Result.failure("数据异常");
            }
        }
        return Result.success(childTemplateVo);
    }

    /*
     * @Author wzy
     * @Description //TODO 生产完工发起
     * @Date 2021/8/20 18:02
     * @Param * @param: workOrderNumber
     * @return com.lzy.wzy.result.Result<org.apache.poi.ss.formula.functions.T>
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<T> doInitiateCompletion(String workOrderNumber, String templateId) {
        String orderStatus = workMapper.getWorkOrderStatus(workOrderNumber);
        Integer count = userMapper.getApproveStatus(workOrderNumber,1);
        if (!MyConstant.WorkOrderStatus.InSystem.equals(orderStatus) ||
                count > 0) {
            return Result.failure("发起失败,或以提交完工");
        }
        MyUsernamePasswordToken token = (MyUsernamePasswordToken) SecurityContextHolder.getContext().getAuthentication();
        String userId = String.valueOf(token.getPrincipal());
        //启动任务
        String proIntsId = startTask(userId, workOrderNumber);
        //生成审批编号
        Random random = new Random();
        StringBuilder buffer=new StringBuilder();
        for (int i = 0; i < 6; i++) {
            buffer.append(random.nextInt(10));
        }
        String id= LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + "0"+ buffer.toString();
        //保存审批信息
        userMapper.saveApproveInfo(id,workOrderNumber,userId,proIntsId,MyConstant.ApproveStatus.MODERATED,"结案审核",LocalDateTime.now());
        return Result.success("发起成功");
    }

    /*
     * @Author wzy
     * @Description //TODO 删除未被使用的三级模板
     * @Date 2021/8/20 18:02
     * @Param * @param: templateId
     * @param: reason
     * @return com.lzy.wzy.result.Result<org.apache.poi.ss.formula.functions.T>
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<T> doDeleteLevelThreeTemplate(int templateId, String reason) {
        String name = templateMapper.getLevelThreeTemplateNameById(templateId);
        if (templateMapper.getLevelThreeMappingCount(templateId) == 0
                && templateMapper.deleteLevelThreeTemplate(templateId) > 0) {
            workOrderUtils.saveBulletin("删除工步模板：", name, reason);
            return Result.success("删除成功");
        }
        return Result.failure("删除失败");
    }

    /*
     * @Author wzy
     * @Description //TODO 删除未被使用的二级模板
     * @Date 2021/8/20 18:03
     * @Param * @param: templateId
     * @param: reason
     * @return com.lzy.wzy.result.Result<org.apache.poi.ss.formula.functions.T>
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<T> doDeleteLevelTwoTemplate(int templateId, String reason) {
        String key = level2key(templateId);
        String name = templateMapper.getLevelTwoTemplateNameById(templateId);
        if (templateMapper.getLevelTwoMappingCount(templateId) == 0
                && templateMapper.deleteLevelTwoTemplate(templateId) > 0
                && templateMapper.deleteLevelTwoTemplateMapping(templateId) > 0) {
            stringRedisTemplate.delete(key);
            workOrderUtils.saveBulletin("删除工序模板：", name, reason);
            return Result.success();
        }
        return Result.failure();
    }

    /*
     * @Author wzy
     * @Description //TODO 获取所有未被使用的三级模板
     * @Date 2021/8/20 18:03
     * @Param * @param:
     * @return com.lzy.wzy.result.Result<java.util.List<com.lzy.wzy.model.LevelOneTemplateBean>>
     **/
    @Override
    public Result<List<LevelOneTemplateBean>> doGetUnusedThreeLevelTemplates() {
        return Result.success(templateMapper.getUnusedThreeLevelTemplates());
    }

    /*
     * @Author wzy
     * @Description //TODO 获取所有未被使用的二级模板
     * @Date 2021/8/20 18:03
     * @Param * @param:
     * @return com.lzy.wzy.result.Result<java.util.List<com.lzy.wzy.model.LevelOneTemplateBean>>
     **/
    @Override
    public Result<List<LevelOneTemplateBean>> doGetUnusedTwoLevelTemplates() {
        return Result.success(templateMapper.getUnusedTwoLevelTemplates());
    }

    /*
     * @Author wzy
     * @Description //TODO 生产信息统计
     * @Date 2021/8/20 18:04
     * @Param * @param: year
     * @param: month
     * @param: productCode
     * @return com.lzy.wzy.result.Result<java.util.List<com.lzy.wzy.vo.EchartsVo>>
     **/
    @Override
    public Result<List<EchartsVo>> doStatisticsOfFinishedMachines(int year, int month, int day, String productCode) {

//        LocalDate first = workMapper.getFirstRecord();
//        LocalDate last = workMapper.getLastRecord();
        if (month < 1
                || month > 12
                || day < 1
                || day > 31) {
            return Result.failure("非法时间");
        }
        productCode = productCode.trim();

        List<PtInfo> ptInfos = templateMapper.getProductTemplateDataByCode(productCode);
        Map<String, Integer> re = null;
        boolean flag = true;
        if (ptInfos.isEmpty()) {
            //pcodeTempBeans = templateMapper.queryReworkTemplateIdByCode(productCode);
            //if (pcodeTempBeans.isEmpty()) {
            Integer quantity = workMapper.getProductQuantityByProductCode(productCode);
            re = new LinkedHashMap<>();
            re.put(MyConstant.WorkOrderStatus.ADD_IN_PRODUCTION, 0);
            re.put(MyConstant.WorkOrderStatus.ADDED_COMPLETION, 0);
            re.put(MyConstant.WorkOrderStatus.ADD_STORAGE, 0);
            re.put(MyConstant.WorkOrderStatus.TO_BE_PRODUCED, quantity);
            re.put(MyConstant.WorkOrderStatus.IN_TOTAL, 0);
            re.put(MyConstant.WorkOrderStatus.TOTAL_FINISHED, 0);
            re.put(MyConstant.WorkOrderStatus.TOTAL_STORAGE, 0);
            flag = false;
            //}
        }
        String date = String.format("%02d", year) + "-" + String.format("%02d", month) + "-" + String.format("%02d", day);
        try {
            LocalDate.parse(date);
        } catch (DateTimeException e) {
            return Result.failure("日期选择错误");
        }
        if (flag) {
            LocalDate now = LocalDate.parse(date);
            ProductStatBean productStat = workMapper.getProductStat(productCode, now);
            if (productStat != null) {
                re = new LinkedHashMap<>();
                re.put(MyConstant.WorkOrderStatus.ADD_IN_PRODUCTION, productStat.getInsystem());
                re.put(MyConstant.WorkOrderStatus.ADDED_COMPLETION, productStat.getFinished());
                re.put(MyConstant.WorkOrderStatus.ADD_STORAGE, productStat.getStore());
                re.put(MyConstant.WorkOrderStatus.TO_BE_PRODUCED, productStat.getToBeProduced());
                re.put(MyConstant.WorkOrderStatus.IN_TOTAL, productStat.getTotalInsystem());
                re.put(MyConstant.WorkOrderStatus.TOTAL_FINISHED, productStat.getTotalFinished());
                re.put(MyConstant.WorkOrderStatus.TOTAL_STORAGE, productStat.getTotalStore());
            } else {
                re = workOrderUtils.pack(date, ptInfos, year, month, productCode);
            }
        }
        String format;
        float val;
        List<EchartsVo> reList = new ArrayList<>();
        EchartsVo echartsVo;
        int size;
        BigDecimal re1;
        BigDecimal re2 = new BigDecimal(Float.toString(100));
        Integer quantity = workMapper.getProductQuantityByProductCode(productCode);
        for (Map.Entry<String, Integer> entry : re.entrySet()) {
            val = 0f;
            echartsVo = new EchartsVo();
            size = entry.getValue();
            if (size > 0) {
                format = String.format("%.4f", size / (float) quantity);
                re1 = new BigDecimal(format);
                val = re1.multiply(re2).floatValue();
            }
            if (size == quantity) {
                val = 100f;
            }
            echartsVo.setValue(size);
            echartsVo.setName(entry.getKey() + "：" + size + "台(" + val + "%)");
            reList.add(echartsVo);
        }
        return Result.success(reList);
    }



    @Override
    public Result<T> doRemoveProductCodingAndTemplateMapping(String productCode, int templateId) {
        if (templateMapper.deleteCodeTemplateMapping(productCode, templateId) > 0) {
            return Result.success("解除成功");
        }
        return Result.failure("解除失败");
    }

    /*
     * @Author wzy
     * @Description //TODO 生产报告导出
     * @Date 2021/8/23 14:00
     * @Param * @param: Result
     * @return void
     **/
    @Override
    public void doProductionReportExport(HttpServletResponse response, int year, int month, int day, int type) throws Exception {
        List<String> productCodes = workMapper.getAllProductCode();
        if (productCodes.isEmpty()) {
            throw new RuntimeException("没有任何数据");
        }
        String time = null;
        switch (type) {
            case 2:
                time = String.valueOf(year);
                break;
            case 3:
                time = String.valueOf(year) + month;
                break;
            case 4:
                time = String.format("%02d", year) + "-" + String.format("%02d", month) + "-" + String.format("%02d", day);
                break;
        }
        Map<String, Map<String, Map<String, Integer>>> map = new LinkedHashMap<>();
        Map<String, Map<String, Integer>> temp;
        Map<String, Integer> child;
        ProductReportStatBean data;
        for (String code : productCodes) {
            List<String> workOrderNumbers = workMapper.getWorkOrderByCode(code);
            temp = new LinkedHashMap<>();
            for (String number : workOrderNumbers) {
                data = workMapper.getReportStatData(code, number, time, type);
                if (data != null) {
                    child = new LinkedHashMap<>();
                    child.put(MyConstant.WorkOrderStatus.ADD_IN_PRODUCTION, data.getInsystem());
                    child.put(MyConstant.WorkOrderStatus.ADDED_COMPLETION, data.getFinished());
                    child.put(MyConstant.WorkOrderStatus.ADD_STORAGE, data.getStore());
                    child.put(MyConstant.WorkOrderStatus.TO_BE_PRODUCED, data.getToBeProduced());
                    child.put(MyConstant.WorkOrderStatus.IN_TOTAL, data.getTotalInsystem());
                    child.put(MyConstant.WorkOrderStatus.TOTAL_FINISHED, data.getTotalFinished());
                    child.put(MyConstant.WorkOrderStatus.TOTAL_STORAGE, data.getTotalStore());
                    temp.put(number, child);
                }
            }
            if (!temp.isEmpty()) {
                map.put(code, temp);
            }
        }
        if (map.isEmpty()) {
            //要导出的数据
            map = workOrderUtils.fillPack(year, month, day, type);

            if (map.isEmpty()) {
                throw new RuntimeException("没有可导出数据");
            }
        }
        //封装导出excel表格
        workOrderUtils.exportExcel(response, map);
    }


    @Override
    public Result<String> doGetSingleData(int templateId, String filed, String id) throws Exception {
        String tableName = templateMapper.queryTableNameByTemplateId(templateId);
        return Result.to(ResponseCode.SUCCESS.getCode(),ResponseCode.SUCCESS.getMsg(),templateMapper.getSingleData(tableName, filed, workOrderUtils.decode(id)));
    }


    @Override
    public Result<String> doDisabledTemplate(int templateId) {
        if (templateMapper.updateTemplateIdf(1, templateId, 0) > 0) {
            return Result.to(ResponseCode.SUCCESS.getCode(), "禁用成功", MyConstant.TemplateStatus.DISABLED);
        }
        return Result.failure("禁用失败");
    }

    @Override
    public Result<String> doEnabledTemplate(int templateId) {
        if (templateMapper.updateTemplateIdf(0, templateId, 1) > 0) {
            return Result.to(ResponseCode.SUCCESS.getCode(), "启用成功", MyConstant.TemplateStatus.IS_ENABLED);
        }
        return Result.failure("启动失败");
    }


    private String startTask(String id, String workOrderNumber) {

        List<User> list = identityService.createUserQuery().memberOfGroups(MyConstant.ApproveGroup.groups).list();

        Map<String, List<User>> collect = list.stream().collect(Collectors.groupingBy(User::getTenantId));
        List<String> prl=new ArrayList<>();
        collect.get("16").forEach(u->prl.add(u.getId()));
        List<String> qsl=new ArrayList<>();
        collect.get("28").forEach(u->qsl.add(u.getId()));
        List<String> ql=new ArrayList<>();
        collect.get("17").forEach(u->ql.add(u.getId()));
        List<String> cl=new ArrayList<>();
        collect.get("26").forEach(u->cl.add(u.getId()));
        List<String> pl=new ArrayList<>();
        collect.get("2").forEach(u->pl.add(u.getId()));

        Map<String, Object> map = new HashMap<>();
        map.put("productList", prl);
        map.put("qualityList", ql);
        map.put("quaList", qsl);
        map.put("craftList", cl);
        map.put("planList", pl);
        map.put("productRole", id);
        workMapper.updateWorkOrderIdentifier(0, workOrderNumber);
        ProcessInstance approve = runtimeService.startProcessInstanceByKey("work_approve_sc", map);
//        String[] emails = userMapper.batchQueryEmail(productList);
//        FoxMailMessage foxMailMessage = new FoxMailMessage();
//        foxMailMessage.setSubject("");
        log.info("开启工单审批，流程id {}", approve.getId());
        return approve.getId();
    }

    private List<List<Object>> packageMap(List<Map<String, Object>> resultList) {
        List<Object> t2;
        List<List<Object>> r2 = new ArrayList<>();
        for (Map<String, Object> map : resultList) {
            t2 = new ArrayList<>(map.values());
            r2.add(t2);
        }
        return r2;
    }

    private List<Map<String, Object>> handlerMap(Map<String, Object> fieldMap, List<Map<String, Object>> resultList) {
        String key;
        Map<String, Object> reMap;
        List<Map<String, Object>> relist = new LinkedList<>();
        for (Map<String, Object> map : resultList) {
            reMap = new LinkedHashMap<>();
            for (Map.Entry<String, Object> entry : fieldMap.entrySet()) {
                key = entry.getKey();
                reMap.put(key, map.getOrDefault(key, ""));
            }
            relist.add(reMap);
        }
        return relist;
    }

    private List<LinkedHashMap<String, Object>> processData(String tableName, List<String> fields, String workOrderNumber) {
        List<LinkedHashMap<String, Object>> bodyData;
        if (templateMapper.existTable(tableName) > 0) {
            bodyData = templateMapper.queryTemplateBodyData(tableName, fields, workOrderNumber);
            if (null == bodyData) {
                bodyData = new ArrayList<>();
            }
        } else {
            bodyData = new ArrayList<>();
        }
        return bodyData;
    }

    private String level2key(int val) {
        return CHILD_TEMPLATE_KEY + val;
    }

    private String level1Key(int val) {
        return TEMPLATE_KEY + val;
    }
}
